//
// Project werewolf: http_handler.cpp
// Created by alfielin on 2021/11/16.
//

#include "werewolf/constants.cpp"
#include "util/basic_filter.cpp"
#include "werewolf/game/room_manager.cpp"
#include <initializer_list>
#include <stdexcept>

namespace nz {
namespace werewolf {
namespace api {

void set_data (const HttpContextPtr &ctx, std::initializer_list<std::pair<std::string, nlohmann::json>> kvs) {
    nlohmann::json data;
    for (const auto &pp: kvs) {
        data[pp.first] = pp.second;
    }
    ctx->response->json[DATA] = data;
}

static auto &manager = RoomManager::get();

int hello_world (const HttpContextPtr &ctx) {
    LOGGER->error("Hello world");
    LOGGER->info("{}:{}", ctx->request->client_addr.ip.c_str(), ctx->request->client_addr.port);
    LOGGER->info("Request {}", ctx->request->Dump(true, true).c_str());
    ctx->set("data", hv::Json({{ "int",     1 },
                               { "double",  3.14 },
                               { "strings", { "aa", "bb", "cc" }}}));
    throw std::runtime_error("good night");
    return HTTP_STATUS_OK;
}

/**
 * @path /createRoom
 * @param userid, config
 * @return { roomid: int }
 */
int create_room (const HttpContextPtr &ctx) {
    std::string userid = ctx->get("userid");
    std::vector<int> config = ctx->request->json.at("config");
    int roomid = manager.create_room(userid, GameConfig(config));
    set_data(ctx, {{ "roomid", roomid }});
    return HTTP_STATUS_OK;
}

/**
 * @path /joinRoom
 * @param userid, roomid
 * @return { role: int }
 */
int join_room (const HttpContextPtr &ctx) {
    std::string userid = ctx->get("userid");
    int roomid = ctx->request->json.at("roomid");
    auto room = manager.get_room(roomid);
    int role = room->join(userid);
    set_data(ctx, {{ "role", role }});
    return HTTP_STATUS_OK;
}

/**
 * @path /exitRoom
 * @param userid
 * @return null
 */
int exit_room (const HttpContextPtr &ctx) {
    std::string userid = ctx->get("userid");
    manager.exit_room(userid);
    return HTTP_STATUS_OK;
}


/**
 * @path /takeAction
 * @param userid, action, targets
 * @return { res:[int] }
 */
int take_action (const HttpContextPtr &ctx) {
    std::string userid = ctx->get("userid");
    int action = ctx->request->json.at("action");
    std::vector<std::string> targets = ctx->request->json.at("targets");
    auto room = manager.get_room_by_userid(userid);
    if (!room) {
        ctx->set(CODE, ERRCODE::XNO_SUCH_USER);
        ctx->set(MSG, ERRMSG::XNO_SUCH_USER);
        return HTTP_STATUS_OK;
    }
    // TODO check if the role has permission to wake up now
    auto ret = room->take_action(ActionT(action), userid, targets);
    if (ret == decltype(ret)({ -1 })) {

        ctx->set(CODE, ERRCODE::XINVALID_OPERATION);
        ctx->set(MSG, ERRCODE::XINVALID_OPERATION);
    } else {
        set_data(ctx, {{ "res", ret }});
    }
    return HTTP_STATUS_OK;
}

/**
 * @path /nightDeath
 * @param userid
 * @return { res: [string] }
 */
int get_night_death_list (const HttpContextPtr &ctx) {
    std::string userid = ctx->get("userid");
    auto room = manager.get_room_by_userid(userid);
    if (!room) {
        ctx->set(CODE, ERRCODE::XNO_SUCH_ROOM);
        ctx->set(MSG, ERRMSG::XNO_SUCH_ROOM);
        return HTTP_STATUS_OK;
    }
    auto ret = room->get_night_death_list();
    set_data(ctx, {{ "res", ret }});
    return HTTP_STATUS_OK;
}


}
}
}
